﻿using System.Drawing.Imaging;
using SpinnakerNET;
using SpinnakerNET.GenApi;

namespace Om.Camera;

public class SpinnakerCamera : IBaseCamera
{
    private readonly string _imgSuffix = "_sp";
    public event EventHandler<bool>? ConnectionChanged;
    private bool _isConnected;
    public bool IsConnected
    {
        get => _isConnected;
        private set
        {
            if (_isConnected != value)
            {
                _isConnected = value;
                ConnectionChanged?.Invoke(this, value);
            }
        }
    }
    public event Action<byte[]>? FrameReceived;

    public string Id { get; private set; }

    public Task<List<string>> GetCameraList()
    {
        _cameraDict.Clear();
        // 从系统中获取相机列表
        //if (spinnakerSystem == null)
            spinnakerSystem = new ManagedSystem();
        var camList = spinnakerSystem.GetCameras();
        for (var i = 0; i < camList.Count; i++)
        {
            var cam = camList[i];
            _cameraDict.Add($"Camera {i+1}",cam);
        }

        return Task.FromResult(_cameraDict.Keys.ToList());
    }

    public async Task Connect(string cameraIpOrName)
    {
        // 从系统中获取相机列表
        if (!_cameraDict.Any())
            await GetCameraList();
        // 注释：打印检测到的相机数量
        // Console.WriteLine("Number of cameras detected: {0}", camList.Count);
        if (!_cameraDict.ContainsKey(cameraIpOrName))
            throw new Exception("Camera not found");
        // 假设取列表中第一个相机
        cam = _cameraDict[cameraIpOrName];
        if (!cam.IsInitialized()) cam.Init();
        // 注释：打印已初始化的相机型号和序列号
        // Console.WriteLine("Initialized Camera:{0} Serial:{1} ", cam.DeviceModelName, cam.DeviceSerialNumber);
        ConfigureCamera(cam);
        ConfigureImageEvents(cam, ref myImageEventListener);
        ConfigureGVCPHeartbeat(cam, false);
        cam.BeginAcquisition();
        // 注释：打印开始采集图像
        // Console.WriteLine("Acquisition Started");

        Id = cameraIpOrName;
        IsConnected = true;
    }

    public Task Disconnect()
    {
        CleanupSpinnaker();
        IsConnected = false;
        return Task.CompletedTask;
    }


    public async Task Capture(string fileName)
    {
        try
        {
            _currentImage.Save(fileName);
        }
        catch (Exception ex) { }
    }

    public bool CanSetExposure => true;
    public async Task<bool> SetAutoExposure(bool isAutoExposure)
    {
        return false;
    }

    public async Task<bool> SetExposureValue(int val)
    {
        try
        {
            var nodeMap = cam.GetNodeMap();
            var iExposureTime = nodeMap.GetNode<IFloat>("ExposureTime");
            if (iExposureTime != null)
            {
                iExposureTime.Value = val;
                return true;
            }
        }
        catch (Exception e)
        {
        }
        return false;
    }

    public async Task<int> GetExposureValue()
    {
        try
        {
            var nodeMap = cam.GetNodeMap();
            var iExposureTime = nodeMap.GetNode<IFloat>("ExposureTime");
            if (iExposureTime != null)
                return (int)iExposureTime.Value;
        }
        catch (Exception e)
        {
        }
        return 0;
    }

    #region MyRegion

    // Spinnaker系统对象
    private ManagedSystem spinnakerSystem;

    // 相机列表
    private Dictionary<string, IManagedCamera> _cameraDict = new();

    // 当前使用的相机
    private IManagedCamera cam;

    // 图像事件监听器
    private ImageEventListener myImageEventListener;

    // 信号量，用于控制并发访问
    private SemaphoreSlim sema = new(1);

    // 当前帧的位图
    private IManagedImage _currentImage;

    ///// <summary>
    /////     初始化Spinnaker系统
    ///// </summary>
    //private void InitializeSpinnaker()
    //{
    //    spinnakerSystem = new ManagedSystem();
    //    // 打印当前库版本
    //    //LibraryVersion spinVersion = spinnakerSystem.GetLibraryVersion();
    //    // 注释：打印Spinnaker库版本
    //    // Console.WriteLine(
    //    //    "Spinnaker library version: {0}.{1}.{2}.{3}",
    //    //    spinVersion.major,
    //    //    spinVersion.minor,
    //    //    spinVersion.type,
    //    //    spinVersion.build);
    //}

    /// <summary>
    ///     配置图像事件
    /// </summary>
    /// <param name="cam">相机对象</param>
    /// <param name="eventListenerToConfig">图像事件监听器</param>
    /// <returns>配置结果，0表示成功，-1表示失败</returns>
    private int ConfigureImageEvents(IManagedCamera cam, ref ImageEventListener eventListenerToConfig)
    {
        var result = 0;
        try
        {
            eventListenerToConfig = new ImageEventListener(cam, ref sema);
            cam.RegisterEventHandler(eventListenerToConfig);
            eventListenerToConfig.ManagedImageReceived += EventListenerToConfigOnManagedImageReceived;
            // 注释：图像事件处理程序已注册
            // Console.WriteLine("***Image Event Handler Registered***");
        }
        catch (SpinnakerException ex)
        {
            // 注释：捕获到Spinnaker异常，打印错误信息
            // Console.WriteLine("Error: {0}", ex.Message);
            result = -1;
        }

        return result;
    }

    private void EventListenerToConfigOnManagedImageReceived(IManagedImage obj)
    {
        _currentImage = obj;
        using var ms = new MemoryStream();
        // 将 Bitmap 对象保存到 MemoryStream 中，指定图片格式
        obj.bitmap.Save(ms, ImageFormat.Jpeg);
        // 将 MemoryStream 中的数据转换为 byte[]
        FrameReceived?.Invoke(ms.ToArray());
    }

    /// <summary>
    ///     配置GVCP心跳
    /// </summary>
    /// <param name="cam">相机对象</param>
    /// <param name="enable">是否启用心跳</param>
    /// <returns>配置结果，0表示成功，-1表示失败</returns>
    private static int ConfigureGVCPHeartbeat(IManagedCamera cam, bool enable)
    {
        // 获取TL设备节点映射
        var nodeMapTLDevice = cam.GetTLDeviceNodeMap();
        // 获取GenICam节点映射
        var nodeMap = cam.GetNodeMap();

        var iDeviceType = nodeMapTLDevice.GetNode<IEnum>("DeviceType");
        var iDeviceTypeGEV = iDeviceType.GetEntryByName("GigEVision");
        // 检查是否为GigEVision相机
        if (iDeviceType != null && iDeviceType.IsReadable)
        {
            if (iDeviceType.Value == iDeviceTypeGEV.Value)
            {
                if (enable)
                {
                    // 注释：重置心跳
                    // Console.WriteLine("Resetting heartbeat");
                }

                // 注释：禁用心跳
                // Console.WriteLine("Disabling heartbeat");
                var iGEVHeartbeatDisable = nodeMap.GetNode<IBool>("GevGVCPHeartbeatDisable");
                if (iGEVHeartbeatDisable == null || !iGEVHeartbeatDisable.IsWritable)
                {
                    // 注释：无法禁用相机心跳，继续执行，可能不是致命错误
                    // Console.WriteLine(
                    //    "Unable to disable heartbeat on camera. Continuing with execution as this may be non - fatal...");
                }
                else
                {
                    iGEVHeartbeatDisable.Value = enable;

                    if (!enable)
                    {
                        // 注释：本次运行已禁用心跳超时，允许暂停和单步执行代码而不会因缺少心跳寄存器读取导致相机断开连接
                        // Console.WriteLine("         Heartbeat timeout has been disabled for this run. This allows pausing ");
                        // Console.WriteLine("         and stepping through  code without camera disconnecting due to a lack ");
                        // Console.WriteLine("         of a heartbeat register read.");
                    }
                    // 注释：已启用心跳超时
                    // Console.WriteLine("         Heartbeat timeout has been enabled.");
                    // 注释：换行
                    // Console.WriteLine();
                }
            }
        }
        else
        {
            // 注释：无法访问TL设备节点映射，终止操作
            // Console.WriteLine("Unable to access TL device nodemap. Aborting...");
            return -1;
        }

        return 0;
    }

    /// <summary>
    ///     配置相机
    /// </summary>
    /// <param name="cam">相机对象</param>
    private void ConfigureCamera(IManagedCamera cam)
    {
        var snodeMap = cam.GetTLStreamNodeMap();
        var iHandlingMode = snodeMap.GetNode<IEnum>("StreamBufferHandlingMode");
        if (iHandlingMode != null && iHandlingMode.IsWritable && iHandlingMode.IsReadable)
        {
            // 默认是最旧优先，设置为最新优先
            var iHandlingModeEntry = iHandlingMode.GetEntryByName("NewestOnly");
            iHandlingMode.Value = iHandlingModeEntry.Value;
            // 注释：设置相机缓冲区处理模式为最新优先，并打印相机序列号
            // Console.WriteLine("Camera Serial: {0} buffer handling mode set to NewestOnly", cam.DeviceSerialNumber);
        }
    }


    /// <summary>
    ///     清理Spinnaker资源
    /// </summary>
    private void CleanupSpinnaker()
    {
        try
        {
            // 在释放系统之前清除相机列表
            if (cam.IsValid())
            {
                cam.UnregisterEventHandler(myImageEventListener);
                cam.EndAcquisition();
                // 注释：打印图像流停止
                // Console.WriteLine("Stream Stopped");

                // 重新启用心跳
                ConfigureGVCPHeartbeat(cam, true);
                cam.DeInit();
                _cameraDict.Clear();
            }

            // 释放系统资源
            spinnakerSystem.Dispose();
        }
        catch (SpinnakerException ex)
        {
            // 注释：清理过程中捕获到Spinnaker异常，打印异常信息
            // Console.WriteLine("Exception during cleanup: {0}", ex);
        }
    }

    #endregion
}

internal class ImageEventListener : ManagedImageEventHandler
{
    // 双缓冲列表
    private readonly List<IManagedImage> ConvertList;

    // 设备序列号
    private string deviceSerialNumber;

    // 显示互斥信号量
    private readonly SemaphoreSlim displayMutex;

    // 图像计数
    public int imageCnt;

    // 图像处理器
    private readonly IManagedImageProcessor processor;

    /// <summary>
    ///     构造函数
    /// </summary>
    /// <param name="cam">相机对象</param>
    /// <param name="displayMutexInput">显示互斥信号量</param>
    public ImageEventListener(IManagedCamera cam, ref SemaphoreSlim displayMutexInput)
    {
        // 双缓冲
        ConvertList = new List<IManagedImage>();
        ConvertList.Add(new ManagedImage());
        ConvertList.Add(new ManagedImage());

        // 初始化图像计数器为0
        imageCnt = 0;
        displayMutex = displayMutexInput;
        deviceSerialNumber = "";

        // 获取设备序列号
        var nodeMap = cam.GetTLDeviceNodeMap();
        var iDeviceSerialNumber = nodeMap.GetNode<IString>("DeviceSerialNumber");
        if (iDeviceSerialNumber != null && iDeviceSerialNumber.IsReadable)
            deviceSerialNumber = iDeviceSerialNumber.Value;
        // 注释：打印为指定序列号的相机初始化图像事件
        // Console.WriteLine("ImageEvent initialized for camera serial: {0}", deviceSerialNumber);
        processor = new ManagedImageProcessor();
    }

    // 帧接收事件
    public event Action<IManagedImage> ManagedImageReceived;

    /// <summary>
    ///     析构函数，清理双缓冲资源
    /// </summary>
    ~ImageEventListener()
    {
        // 清理双缓冲
        if (ConvertList != null)
            foreach (var item in ConvertList)
                item.Dispose();
    }

    /// <summary>
    ///     图像事件处理方法
    /// </summary>
    /// <param name="image">接收到的图像</param>
    protected override void OnImageEvent(ManagedImage image)
    {
        // 示例控制台打印，每100帧打印一次，避免控制台日志过多导致性能下降
        //if (image.FrameID % 100 == 0)
        //{
        //    // 注释：打印图像事件信息，每100帧打印一次
        //    // Console.WriteLine("Image event! (We are only printing every 100 counts..) FrameID:{0}, ImageStatus:{1}",
        //    //    image.FrameID,
        //    //    image.ImageStatus.ToString()
        //    //    );
        //}

        // 在预分配的两个图像之间交替（双缓冲或乒乓缓冲），确保位图在PictureBox渲染中途不会被覆盖，避免在某些绘图事件或调整PictureBox大小时引发异常
        var doubleBufferImage = ConvertList[(int)image.FrameID % 2];

        // 互斥锁可缓解图像事件到达速度快于图像处理速度时的冲突
        if (displayMutex.Wait(TimeSpan.Zero))
            try
            {
                using (var convertedImage = processor.Convert(image, PixelFormatEnums.BGR8))
                {
                    doubleBufferImage.DeepCopy(convertedImage);
                    ManagedImageReceived?.Invoke(doubleBufferImage);
                } // 转换后的图像在离开'using'作用域时释放
            }
            catch (SpinnakerException ex)
            {
                // 注释：捕获到Spinnaker异常，打印异常信息
                // Console.WriteLine("Exception: {0} ", ex);
            }
            finally
            {
                image.Release();
                displayMutex.Release();
            }
        else
            // 如果打印此信息，说明位图/渲染路径不够快
            // 注释：打印由于前一帧仍在处理中，当前帧不进行处理的信息
            // Console.WriteLine("Not processing FrameID: {0} as previous one is still being processed", image.FrameID);
            // 确保释放图像以便重新排队
            image.Release();
    }
}